package com.stylefeng.guns.core.util;

import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.stylefeng.guns.core.cache.CacheKit;
import com.stylefeng.guns.core.common.SmsConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Random;

/**
 * @Auther: Huang Yuehong
 * @Description: 短信服务工具类
 * @Date: 2018/6/20 15:23
 */
public class SmsUtil {

    private static Logger log = LoggerFactory.getLogger(SmsUtil.class);

    // 短信签名
    private static final String SIGN_NAME = "福建省职业经理人行业协会";

    // 注册验证码模板
    private static final String REGISTER_VERIFICATION_CODE_TEMP = "SMS_93360016";
    // 找回密码验证码模板
    private static final String RESET_VERIFICATION_CODE_TEMP = "SMS_94135019";
    // 登录验证码模板
    private static final String LOGIN_VERIFICATION_CODE_TEMP = "SMS_94490009";
    // 用户下单通知模板
    private static final String PLACE_ORDER_TEMP = "SMS_94235027";
    // 用户订单发货通知模板
    private static final String DELIVERY_TEMP = "SMS_94275046";
    // 线下直销商审核通过通知模板
    private static final String OFFLINE_BUSINESS_AUDIT_PASS_TEMP = "SMS_94135031";
    // 线下直销商审核失败通知模板
    private static final String OFFLINE_BUSINESS_AUDIT_FAIL_TEMP = "SMS_94450004";
    // 兑换商品发货通知
    private static final String EXCHANGE_DELIVERY_NOTICE_TEMP = "SMS_109465331";


    // 产品名称:云通信短信API产品,开发者无需替换
    private static final String PRODUCT = "Dysmsapi";
    // 产品域名,开发者无需替换
    private static final String DOMAIN = "dysmsapi.aliyuncs.com";

    // 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
    private static final String ACCESS_KEY_ID = "LTAIIk8vPkj8hH5D";
    private static final String ACCESS_KEYS_ECRET = "FXyB0h96pqnbD7dUrXbU3Cfcn3QFYi";

    // 手机验证码有效时间半小时
    public static final String CACHE_VALID_CODE = "halfHour";

    /**
     * 发送注册验证码短信。
     *
     * @param phoneNumber 目标手机号
     * @param type        类型，详见SmsConstants
     * @return 请求响应结果
     * @throws ClientException
     * @see SmsConstants
     */
    public static SendSmsResponse sendVerificationCode(String phoneNumber, Integer type) throws ClientException {
        SendSmsResponse response;

        if (SmsConstants.SMS_TYPE_REGISTER_CODE.equals(type)) {
            response = doSendSmsRequest(
                    phoneNumber, REGISTER_VERIFICATION_CODE_TEMP, String.format("{\"code\":\"%s\"}", generateCode(phoneNumber))
            );
        } else if (SmsConstants.SMS_TYPE_RESET_CODE.equals(type)) {
            response = doSendSmsRequest(
                    phoneNumber, RESET_VERIFICATION_CODE_TEMP, String.format("{\"code\":\"%s\"}", generateCode(phoneNumber))
            );
        } else if (SmsConstants.SMS_TYPE_LOGIN_CODE.equals(type)) {
            response = doSendSmsRequest(
                    phoneNumber, LOGIN_VERIFICATION_CODE_TEMP, String.format("{\"code\":\"%s\"}", generateCode(phoneNumber))
            );
        } else {
            return null;
        }

        logResponseInfo(response, phoneNumber, type);

        return response;
    }

    /**
     * 发送订单下单通知信息。
     *
     * @param phoneNumber 目标手机号
     * @param orderNo     订单号
     * @return 请求响应结果
     * @throws ClientException
     */
    public static SendSmsResponse sendPlaceOrderMsg(String phoneNumber, String orderNo) throws ClientException {

        SendSmsResponse response = doSendSmsRequest(
                phoneNumber, PLACE_ORDER_TEMP, String.format("{\"orderNo\":\"%s\"}", orderNo)
        );

        logResponseInfo(response, phoneNumber, SmsConstants.SMS_TYPE_PLACE_ORDER);

        return response;
    }

    /**
     * 发送用户订单发货通知信息。
     *
     * @param phoneNumber  目标手机号
     * @param trackingNo   运单单号
     * @param trackingName 快递名称
     * @return 请求响应结果
     * @throws ClientException
     */
    public static SendSmsResponse sendDeliveryMsg(String phoneNumber, String trackingNo, String trackingName) throws ClientException {
        SendSmsResponse response = doSendSmsRequest(
                phoneNumber, DELIVERY_TEMP, String.format("{\"trackingNo\":\"%s\", \"trackingName\":\"%s\"}", trackingNo, trackingName)
        );

        logResponseInfo(response, phoneNumber, SmsConstants.SMS_TYPE_DELIVERY);

        return response;
    }

    /**
     * 发送用户订单发货通知信息。
     *
     * @param phoneNumber    目标手机号
     * @param enterpriseName 企业名称
     * @param trackingNo     运单单号
     * @param trackingName   快递名称
     * @return 请求响应结果
     * @throws ClientException
     */
     public static SendSmsResponse sendExchangeDeliveryMsg(String phoneNumber, String enterpriseName, String trackingNo, String trackingName) throws ClientException {
        SendSmsResponse response = doSendSmsRequest(
                phoneNumber, EXCHANGE_DELIVERY_NOTICE_TEMP, String.format("{\"enterpriseName\":\"%s\", \"trackingNumber\":\"%s\", \"trackingName\":\"%s\"}", enterpriseName, trackingNo, trackingName)
        );

        logResponseInfo(response, phoneNumber, SmsConstants.SMS_TYPE_EXCHANGE_DELIVERY);

        return response;
     }

    /**
     * 发送线下直销商审核结果信息。
     *
     * @param phoneNumber 目标手机号
     * @param auditResult 审核结果
     * @return 请求响应结果
     * @throws ClientException
     */
     public static SendSmsResponse sendOfflineBusinessAuditMsg(String phoneNumber, Integer auditResult) throws ClientException {

        String tempCode = SmsConstants.OFFLINE_BUSINESS_AUDIT_PASS.equals(auditResult)
                ? OFFLINE_BUSINESS_AUDIT_PASS_TEMP : OFFLINE_BUSINESS_AUDIT_FAIL_TEMP;

        SendSmsResponse response = doSendSmsRequest(phoneNumber, tempCode, String.format("{\"phone\":\"%s\"}", ""));

        logResponseInfo(response, phoneNumber, SmsConstants.SMS_TYPE_OFFLINE_BUSINESS_AUDIT);

        return response;
     }

    // ========================================================================================
    //                                 Private Method
    // ========================================================================================

    /**
     * 执行发送短信请求。
     *
     * @param phoneNumber   目标手机号
     * @param tempCode      模板代码
     * @param templateParam 模板参数
     */
    private static SendSmsResponse doSendSmsRequest(String phoneNumber, String tempCode, String templateParam) throws ClientException {
        // 可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");

        try {
            // 初始化acsClient,暂不支持region化
            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", ACCESS_KEY_ID, ACCESS_KEYS_ECRET);
            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", PRODUCT, DOMAIN);
            IAcsClient acsClient = new DefaultAcsClient(profile);

            // 组装请求对象-具体描述见控制台-文档部分内容
            SendSmsRequest request = new SendSmsRequest();
            // 必填:待发送手机号
            request.setPhoneNumbers(phoneNumber);
            // 必填:短信签名-可在短信控制台中找到
            request.setSignName(SIGN_NAME);
            // 必填:短信模板-可在短信控制台中找到
            request.setTemplateCode(tempCode);
            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
            request.setTemplateParam(templateParam);


            // 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
            // request.setOutId("yourOutId");

            return acsClient.getAcsResponse(request);
        } catch (ClientException e) {
            log.error("#### 发送短信验证码发生异常： ####", e);
            throw e;
        }
    }

    /**
     * 生成验证码，以目标手机号为key值缓存验证码信息
     *
     * @param phoneNumber 目标手机号
     * @return 四位数字验证码
     */
    private static String generateCode(String phoneNumber) {
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            code.append(random.nextInt(10));
        }

        CacheKit.put(CACHE_VALID_CODE, phoneNumber, code.toString());
        return code.toString();
    }

    /**
     * 记录发送短信响应信息日志。
     *
     * @param response    响应信息
     * @param phoneNumber 目标手机号
     * @param type        短信类型
     */
    private static void logResponseInfo(SendSmsResponse response, String phoneNumber, Integer type) {
        saveSmsRecord(phoneNumber, type, response);
        if (SmsConstants.SUCCESS_CODE.equals(response.getCode())) {
            log.info("#### 发送短信验证码成功 ####");
        } else {
            log.error("#### 发送短信验证码失败，Code = 【{}】, Message = 【{}】 ####", response.getCode(), SmsConstants.SMS_RESPONSE_MSG.get(response.getCode()));
        }
    }

    /**
     * 保存短信发送记录。
     *
     * @param phoneNumber 目标手机号
     * @param type        类型，详见SmsConstants
     * @param response    请求响应结果
     * @see SmsConstants
     */
    private static void saveSmsRecord(String phoneNumber, Integer type, SendSmsResponse response) {
        /*SysSmsRecord record = new SysSmsRecord();
        record.setPhoneNumber(phoneNumber);
        record.setType(type);
        record.setCode(response.getCode());
        record.setMessage(SmsConstants.SMS_RESPONSE_MSG.get(response.getCode()));
        record.setBizId(response.getBizId());
        record.setCreateTime(DateUtils.getDefaultTimeStr());

        record.save();*/
    }
}
